#include "opcuaclient.h"
#include <QDebug>

UA_Client* OPCUAClient::m_client = 0;
QMutex OPCUAClient::m_mutex;

void OPCUAClient::dataChangeCallback(
    UA_Client*, UA_UInt32, void* context,
    UA_UInt32 monItemId, void*, UA_DataValue* value
    ) {
    OPCUAClient* instance = static_cast<OPCUAClient*>(context);
    if (!instance || !value ) return;

    // 查找别名
    if (!instance->m_monitoredItems.contains(monItemId)) return;
    QString alias = instance->m_monitoredItems[monItemId];

    // 处理REAL类型（UA_TYPES_FLOAT或UA_TYPES_DOUBLE）
    if (value->value.type == &UA_TYPES[UA_TYPES_FLOAT]) {
        float floatVal = *static_cast<float*>(value->value.data);
        // 调试输出：显示别名和值
        qDebug() << "OPCUAClient回调接收到数据：" << alias << " = " << floatVal;

        // 触发信号
        QMetaObject::invokeMethod(instance, "realValueChanged", Qt::QueuedConnection,
                                  Q_ARG(QString, alias),
                                  Q_ARG(float, floatVal));
    } else if (value->value.type == &UA_TYPES[UA_TYPES_DOUBLE]) {
        double doubleVal = *static_cast<double*>(value->value.data);
        float floatVal = static_cast<float>(doubleVal);
        qDebug() << "OPCUAClient回调接收到数据（DOUBLE转FLOAT）：" << alias << " = " << floatVal;
                QMetaObject::invokeMethod(instance, "realValueChanged", Qt::QueuedConnection,
                                          Q_ARG(QString, alias),
                                          Q_ARG(float, floatVal));
    } else {
                qDebug() << "OPCUAClient回调：未知数据类型" ;
    }
}

OPCUAClient* OPCUAClient::instance() {
    static OPCUAClient* instance = 0;
    if (!instance) {
        QMutexLocker locker(&m_mutex);
        if (!instance) {
            instance = new OPCUAClient();
        }
    }
    return instance;
}

OPCUAClient::OPCUAClient(QObject* parent) : QObject(parent),
    m_connected(false),
    m_subscriptionId(0)
{
    if (!m_client) {
        m_client = UA_Client_new(UA_ClientConfig_default);
    }
}

OPCUAClient::~OPCUAClient() {
    disconnectServer();
    if (m_client) {
        UA_Client_delete(m_client);
        m_client = 0;
    }
}

bool OPCUAClient::connectServer(const QString& endpointUrl) {
    QMutexLocker locker(&m_mutex);
    if (m_connected) return true;

    // 连接服务器
    UA_StatusCode status = UA_Client_connect(m_client, endpointUrl.toUtf8().constData());
    if (status != UA_STATUSCODE_GOOD) {
        qDebug() << "连接失败:" << status;
        m_connected = false;
        return false;
    }

    // 创建订阅（使用默认参数）
    UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
    request.requestedPublishingInterval = 500.0; //发布间隔

    UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(
        m_client, request, this, 0, 0
        );

    status = response.responseHeader.serviceResult;
    if (status == UA_STATUSCODE_GOOD) {
        m_subscriptionId = response.subscriptionId;
        m_connected = true;
        return true;
    } else {
        qDebug() << "创建订阅失败:" << status;
        UA_Client_disconnect(m_client);
        m_connected = false;
        return false;
    }
}

void OPCUAClient::disconnectServer() {
    QMutexLocker locker(&m_mutex);
    if (!m_connected) return;

    // 取消所有订阅
    unsubscribeAll();

    // 删除订阅
    if (m_subscriptionId != 0) {
        UA_DeleteSubscriptionsRequest delReq;
        UA_DeleteSubscriptionsRequest_init(&delReq);
        delReq.subscriptionIdsSize = 1;
        delReq.subscriptionIds = &m_subscriptionId;
        UA_Client_Subscriptions_delete(m_client, delReq);
        m_subscriptionId = 0;
    }

    // 断开连接
    UA_Client_disconnect(m_client);
    m_connected = false;
}

bool OPCUAClient::subscribeReal(const QString& nodeId, const QString& alias) {
    QMutexLocker locker(&m_mutex);
    if (!m_connected || m_subscriptionId == 0) {
        qDebug() << "未连接或订阅未创建";
        return false;
    }

    // 解析节点ID
    UA_NodeId parsedNodeId;
    parseNodeId(nodeId, parsedNodeId);

    // 创建监控项请求
    UA_MonitoredItemCreateRequest monReq = UA_MonitoredItemCreateRequest_default(parsedNodeId);

    // 设置监控属性为值变化（关键参数）
    monReq.itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE;

    // 配置订阅参数
    monReq.requestedParameters.samplingInterval = 100.0;  // 采样间隔（ms）
    monReq.requestedParameters.queueSize = 1;             // 队列大小
    monReq.requestedParameters.discardOldest = true;      // 丢弃旧值

    // 调用简化的单监控项创建函数
    UA_MonitoredItemCreateResult result = UA_Client_MonitoredItems_createDataChange(
        m_client,               // OPC UA客户端
        m_subscriptionId,       // 订阅ID
        UA_TIMESTAMPSTORETURN_BOTH, // 返回时间戳（源时间和服务器时间）
        monReq,                 // 监控项请求
        this,                   // 上下文指针（用于回调中获取客户端实例）
        dataChangeCallback,     // 数据变化回调函数（直接传递函数指针）
        0                 // 删除回调函数（可选，这里不使用）
    );
    // 处理返回结果
    if (result.statusCode == UA_STATUSCODE_GOOD) {
        UA_UInt32 monItemId = result.monitoredItemId;
        QString useAlias = alias.isEmpty() ? nodeId : alias;
        m_monitoredItems[monItemId] = useAlias;
        m_nodeIdMap[nodeId] = monItemId;
        qDebug() << "订阅成功:" << nodeId << " 别名: " << useAlias;
        qDebug()<<monItemId;
        return true;
    } else {
        qDebug() << "订阅失败: " << UA_StatusCode_name(result.statusCode);
        return false;
    }
}

void OPCUAClient::unsubscribeReal(const QString& nodeId) {
    QMutexLocker locker(&m_mutex);
    if (!m_nodeIdMap.contains(nodeId)) return;

    UA_UInt32 monItemId = m_nodeIdMap.take(nodeId);
    UA_DeleteMonitoredItemsRequest delReq;
    UA_DeleteMonitoredItemsRequest_init(&delReq);
    delReq.subscriptionId = m_subscriptionId;
    delReq.monitoredItemIds = &monItemId;
    delReq.monitoredItemIdsSize = 1;
    UA_Client_MonitoredItems_delete(m_client, delReq);
    m_monitoredItems.remove(monItemId);
    qDebug() << "取消订阅:" << nodeId;
}

void OPCUAClient::unsubscribeAll() {
    QMutexLocker locker(&m_mutex);
    if (m_monitoredItems.isEmpty()) return;

    // 批量删除所有监控项
    QVector<UA_UInt32> itemIds;
    QMap<UA_UInt32, QString>::const_iterator it;
    for (it = m_monitoredItems.begin(); it != m_monitoredItems.end(); ++it) {
        itemIds.append(it.key());
    }

    UA_DeleteMonitoredItemsRequest delReq;
    UA_DeleteMonitoredItemsRequest_init(&delReq);
    delReq.subscriptionId = m_subscriptionId;
    delReq.monitoredItemIds = itemIds.data();
    delReq.monitoredItemIdsSize = itemIds.size();
    UA_Client_MonitoredItems_delete(m_client, delReq);
    m_monitoredItems.clear();
    m_nodeIdMap.clear();
}

// 节点ID解析函数
void OPCUAClient::parseNodeId(const QString& nodeId, UA_NodeId& outNodeId) {
    outNodeId = UA_NODEID_STRING(3, const_cast<char*>(nodeId.toUtf8().constData()));
}
